/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package server.votesending;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.Semaphore;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.DatatypeConverter;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.jdom.JDOMException;
import server.votesending.xmlsinger.Vote;
import server.votesending.xmlsinger.XmlDSASigner;
import utils.XMLParser;

public class EchoProtocol implements Runnable {
    
    private static String file = "mydatabase.txt";
    private static final int BUFSIZE = 32; // Size (in bytes) of I/O buffer
    private static int i = 0;
    private static Semaphore semaphore = new Semaphore(1,true);
    
  
    private static void writeVoteToDataBase(byte[] vote) {
       
    }
    
    private static void writeVoteToDataBase(Vote vote){
        
            try {
                semaphore.acquire();
                BufferedWriter out = new BufferedWriter(new FileWriter(file,true));
                Calendar calendar = Calendar.getInstance();
                long milis = calendar.getTimeInMillis();
                out.write("" + milis + " " + vote.getValue()+"\n");
                out.close();
                semaphore.release();
            } catch (InterruptedException ex) {
            Logger.getLogger(EchoProtocol.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
                Logger.getLogger(EchoProtocol.class.getName()).log(Level.SEVERE, null, ex);
            }
         
    }
    private Socket clntSock;               // Socket connect to client
    private Logger logger;                 // Server logger

    public EchoProtocol(Socket clntSock, Logger logger) {
        System.out.println("Tworze nowy echoprotocol");
        this.clntSock = clntSock;
        this.logger = logger;
    }
    
    static private String bytesToString(byte[] bytes){
        return DatatypeConverter.printBase64Binary(bytes);
    }
    
    static private byte[] stringToBytes(String string){
        return DatatypeConverter.parseBase64Binary(string);
    }
    
    public static byte[] getBytesFromDomDocuments(org.w3c.dom.Document  domDocument) throws TransformerConfigurationException, TransformerException{
         TransformerFactory tf = TransformerFactory.newInstance();
         Transformer trans = tf.newTransformer();
         ByteArrayOutputStream stream = new ByteArrayOutputStream();
         trans.transform(new DOMSource(domDocument), new StreamResult(stream));
         return stream.toByteArray();
    }
    
    public static byte[] signVote(byte[] data){
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.SSS");
            Date dt = new Date();
            String S = sdf.format(dt); // formats to 09/23/2009 13:53:28.238

            Vote vote = new Vote(S,bytesToString(data));
             writeVoteToDataBase(vote);
             XmlDSASigner signer = new XmlDSASigner();
             signer.initXml();
             signer.initKeys("certs"+ File.separatorChar+ "mycakeystore.jks", "bskbsk", "bskbsk", "cacert");
                     
                     
             org.w3c.dom.Document signedDocument = signer.xmlSign(vote);
           
            
             return getBytesFromDomDocuments(signedDocument);
             
        }  catch (TransformerConfigurationException ex) {
            Logger.getLogger(EchoProtocol.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TransformerException ex) {
            Logger.getLogger(EchoProtocol.class.getName()).log(Level.SEVERE, null, ex);
        } catch (JDOMException ex) {
            Logger.getLogger(EchoProtocol.class.getName()).log(Level.SEVERE, null, ex);
        } catch (MarshalException ex) {
            Logger.getLogger(EchoProtocol.class.getName()).log(Level.SEVERE, null, ex);
        } catch (XMLSignatureException ex) {
            Logger.getLogger(EchoProtocol.class.getName()).log(Level.SEVERE, null, ex);
        } catch (KeyStoreException ex) {
            Logger.getLogger(EchoProtocol.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(EchoProtocol.class.getName()).log(Level.SEVERE, null, ex);
        } catch (CertificateException ex) {
            Logger.getLogger(EchoProtocol.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnrecoverableEntryException ex) {
            Logger.getLogger(EchoProtocol.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(EchoProtocol.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidAlgorithmParameterException ex) {
            Logger.getLogger(EchoProtocol.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
    public static void handleEchoClient(Socket clntSock, Logger logger) {
        try {
            // Get the input and output I/O streams from socket
            InputStream in = clntSock.getInputStream();
            OutputStream out = clntSock.getOutputStream();
            LengthFramer lf = new LengthFramer(in);

            int totalBytesEchoed = 0; // Bytes received from client
           
            // Receive until client closes connection, indicated by -1
            byte[] echoBuffer = lf.nextMsg();
            
            byte[] result = signVote(echoBuffer);
            writeVoteToDataBase(echoBuffer);
            lf.frameMsg(result, out);
            
            
            logger.info("Client " + clntSock.getRemoteSocketAddress() + ", echoed " + totalBytesEchoed + " bytes.");

        } catch (IOException ex) {
            logger.log(Level.WARNING, "Exception in echo protocol", ex);
        } finally {
            try {
                
                clntSock.close();
            } catch (IOException e) {
            }
        }
    }

    @Override
    public void run() {
        handleEchoClient(clntSock, logger);
    }
}
